﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using EzyThirdLogic.ExtensionMethods;

namespace EzyThirdLogic
{
    /// <summary>
    /// This class takes care of Step 1, 2 of Berstein Algorithm
    /// and Remove SuperFluous Attribute Algorithm.
    /// </summary>
    public static class SynthesizingAlgorithm
    {
        /// <summary>
        /// Given a set of FDs and a left hand side attribute.
        /// We will find the closure of this particular attribute.
        /// </summary>
        /// <param name="fdSet"></param>
        /// <param name="attributes"></param>
        /// <returns></returns>
        public static BitArray AttributeClosure(FunctionalDependencySet fdSet, BitArray attributes)
        {
            BitArray closure = (BitArray)attributes.Clone();

            bool needChange = true;
            while (needChange)
            {
                needChange = false;

                foreach (FunctionalDependency fd in fdSet.FDSet)
                {
                    BitArray lhs = (BitArray)fd.BitDeterminant.Clone();
                    BitArray rhs = (BitArray)fd.BitDependent.Clone();

                    if (lhs.LogicalSize() > 0)
                    {
                        lhs.And(closure);
                        if (lhs.IsEquals(fd.BitDeterminant))
                        {
                            rhs.And(closure);
                            if (!rhs.IsEquals(fd.BitDependent))
                            {
                                closure.Or(fd.BitDependent);
                                needChange = true;
                            }
                        }
                    }
                }
            }

            return closure;
        }

        /// <summary>
        /// Check a particular FD is in the closure or not?
        /// </summary>
        /// <param name="fd"></param>
        /// <param name="fdSet"></param>
        /// <returns></returns>
        public static bool IsMember(FunctionalDependency fd, FunctionalDependencySet fdSet)
        {
            BitArray left = (BitArray)fd.BitDeterminant.Clone();
            BitArray attributeClosure = AttributeClosure(fdSet, left);
            BitArray right = (BitArray)fd.BitDependent.Clone();
            right.And(attributeClosure);
            return right.IsEquals(fd.BitDependent);
        }

        /// <summary>
        /// Check whether right hand side have more than 1 attribute
        /// </summary>
        public static bool IsMultipleRHS(FunctionalDependency fd)
        {
            if (fd.BitDependent.Cardinality() > 1)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Method to separate multiple RHS Attributes to different functional dependency.
        /// {AB->BC} into {AB->B, AB->C}
        /// </summary>
        /// <param name="fdSet"></param>
        /// <param name="fd"></param>
        /// <returns></returns>
        public static void SeparateRHSAttr(FunctionalDependencySet fdSet, FunctionalDependency fd)
        {
            int size = fd.BitDeterminant.Count;
            String left = fd.LeftToStringWithDelimiter();
            //loop throught the attributes on RHS
            for (int i = fd.BitDependent.NextSetBit(0); i >= 0; i = fd.BitDependent.NextSetBit(i + 1))
            {
                String right = "";
                char c;
                int a = 65 + i;
                c = (char)a;
                right += c;
                FunctionalDependency fdTemp = new FunctionalDependency(left, right, size);
                //Add the single RHS Attribute fd to the fdSet
                fdSet.AddFunctionalDependency(fdTemp);
            }
        }

        /// <summary>
        /// Given a set of FDs, this method will return a set of FDs with only single RHS Attributes
        /// </summary>
        /// <param name="fdSet"></param>
        /// <returns></returns>
        public static FunctionalDependencySet AllSingleRHSAttr(FunctionalDependencySet fdSet)
        {
            FunctionalDependencySet newFDSet = new FunctionalDependencySet();
            foreach (FunctionalDependency fd in fdSet.FDSet)
            {
                if (IsMultipleRHS(fd))
                    SeparateRHSAttr(newFDSet, fd);
                else
                    newFDSet.AddFunctionalDependency(fd);
            }
            return newFDSet;
        }

        /// <summary>
        /// Check if there are more than 1 attribute on LHS
        /// </summary>
        /// <param name="fd"></param>
        /// <returns></returns>
        public static bool IsMultipleLHS(FunctionalDependency fd)
        {
            if (fd.BitDeterminant.Cardinality() > 1)
                return true;
            else
                return false;
        }

        /// <summary>
        /// method to remove the extraneous attributes on lhs, an attribute is extraneous in A, lhs of a fd, if 
        /// the attribute is in (A minus attribute) closure on the set of fds. If it is, remove the attribute from lhs
        /// and returns the set of fds with that particular fd having no extraneous attribute
        /// </summary>
        /// <param name="fdSet"></param>
        /// <param name="fd"></param>
        /// <returns></returns>
        public static FunctionalDependencySet SeparateLHSAttr(FunctionalDependencySet fdSet, FunctionalDependency fd)
        {
            //only for FDs with multiple LHS Attributes
            if (IsMultipleLHS(fd))
            {
                int size = fd.BitDeterminant.Length;
                String right = fd.RightToStringWithDelimiter();
                String left = "";

                //loop through attributes on LHS
                for (int i = fd.BitDeterminant.NextSetBit(0); i >= 0; i = fd.BitDeterminant.NextSetBit(i + 1))
                {
                    BitArray leftFD = (BitArray)fd.BitDeterminant.Clone();
                    char c;
                    int a = 65 + i;
                    c = (char)a;
                    BitArray attribute = FunctionalDependency.ToBitArray(c);
                    BitArray attribute2 = FunctionalDependency.ToBitArray(c);
                    leftFD.Xor(attribute);
                    //find the closure of (A minus Attribute) on FDSet
                    BitArray attrClosure = AttributeClosure(fdSet, leftFD);
                    //check if attribute lies in the closure found above
                    attribute.And(attrClosure);
                    //If it does, can remove the extraneous attributes from LHS
                    if (attribute.IsEquals(attribute2))
                    {
                        left += FunctionalDependency.ToStringWithDelimiter(leftFD);
                        //left += fd.Determinant;
                        FunctionalDependency fd1 = new FunctionalDependency(left, right, size);
                        fdSet.RemoveFunctionalDependency(fd);
                        fdSet.AddFunctionalDependency(fd1);
                        //recursive call since FDSet is now modified
                        SeparateLHSAttr(fdSet, fd1);
                        break;
                    }
                }
            }
            return fdSet;
        }

        /// <summary>
        /// given a set of fds, this method will return a set of fds with no extraneous attributes on LHS
        /// </summary>
        /// <param name="fdSet"></param>
        /// <returns></returns>
        public static FunctionalDependencySet RemoveExtraneousAttributes(FunctionalDependencySet fdSet)
        {
            FunctionalDependencySet newFDSet = new FunctionalDependencySet(fdSet);
            foreach (FunctionalDependency fd in fdSet.FDSet)
            {
                newFDSet = SeparateLHSAttr(newFDSet, fd);
            }
            return newFDSet;
        }
    }
}
